查看原文
其他

搞定 RecycleView 自动加载更多、侧滑菜单、添加头部底部

王英豪 鸿洋 2019-04-05

本文作者


作者:王英豪

链接:

http://blog.csdn.net/yhaolpz/article/details/77891594

本文由作者投稿推送。


文章前半部分将如何使用,后半部分为原理以及源码讲解,文章较长,耐心看。


在 动手打造史上最简单的 Recycleview 侧滑菜单 中,萌生了将这种方案封装为一个开源库的想法,旨在实现调用方式最简单,且又不失可定制性。本库最大的特点的是采用了 Glide 简洁明了的链式调用方式,一句代码即可添加侧滑菜单、头部底部等。


特性:


1.自定义侧滑菜单布局 
2.添加头部、底部 
3.轻松实现加载更多 
4.设置 item 间距 
5.多种 item 类型 
6.支持 LinearLayout 及 GridLayout 
7.一句代码实现所有功能


效果:


左侧滑菜单、右侧滑菜单、自定义菜单布局:


  



  


头部、多头部:


    



底部、多底部、加载更多:


  


  



集成:


第 1 步、在工程的 build.gradle 中添加:


allprojects {    repositories {        ...        maven { url 'https://jitpack.io' }    } }


第 2 步、在应用的 build.gradle 中添加:


dependencies {    compile 'com.github.yhaolpz:SlideAdapter:1.0.0' }


1使用


下面通过简单案例演示如何在程序中使用 SlideAdapter,假设 item.xml 为:



数据类为:


public class Bean {    private String info;    public Bean(String info) {        this.info = info;    }    // 省略 get、set 方法... }


数据为:


final List<Bean> data = new ArrayList<>(); for (int i = 0; i < 30; i++) {     data.add(new Bean("我是第" + i + "个item")); }



1.基本写法 :


SlideAdapter.load(data) //加载数据              .item(R.layout.item)  //指定布局    .into(recyclerView);  //填充到recyclerView中



2.数据绑定及事件监听:


SlideAdapter.load(data)    .item(R.layout.item)    .bind(itemBind) //视图绑定    .into(recyclerView);


在 itemBind 中进行数据绑定及控件的事件监听,相当于 Adapter 中的 onBindViewHolder ,实现 ItemBind 时需传入数据类型:



3.添加 item 间距:


SlideAdapter.load(data)              .item(R.layout.item)      .padding(2) //item间距    .bind(itemBind)          .into(recyclerView);


4.添加侧滑菜单:



上面调用的 item 方法为 :


item (int itemLayoutId,      int leftMenuLayoutId, float leftMenuRatio,      int rightMenuLayoutId, float rightMenuRatio)


不添加哪一侧,就把对应参数传入 0 即可。


5.侧滑菜单的数据绑定及事件监听:


菜单布局为 itemView 的一部分,所以对侧滑菜单的数据绑定及事件监听直接在 ItemBind 中进行即可。


比如侧滑菜单布局 menu.xml 为下:



对 rightMenu_Like 控件设置点击事件监听,就像对 item 中的普通控件设置一样:



6.多种 item 布局:



7.添加头部:



8.头部的数据绑定及事件监听:


对头部的数据绑定及事件监听在 HeaderBind 中实现:



9.添加底部:



10.加载更多:



onBottom 方法中的 footer 为最后一个底部,若未添加底部,则 footer 为空。其中 SlideAdapter 的 loadMore() 方法专门用来加载更多数据,需在主线程中调用。


2实现原理


1.如何实现链式调用


虽然这部分并不难,但毕竟是 SlideAdapter 异于其他库的一大特点,简单介绍一下,直接看代码:



SlideAdapter 中以 Builder load(List data) 方法为入口,然后进入 Builder 内部链式调用一系列方法,将配置属性暂时记录在 Builder 中,最后通过 SlideAdapter into(RecyclerView recyclerView) 方法将这一系列配置属性传入到 SlideAdapter 的构造函数中使其配置生效。


2.如何实现侧滑菜单


本库基于一种非常简单的侧滑菜单实现方案:

在 item 布局外部添加一层可以滑动的 HorizontalScrollView ,菜单布局也置于其中

也就是说,本库要做的工作是: 自动在 item 布局外部添加一层可以滑动的 HorizontalScrollView 容器。


我们要考虑的问题有两个:


1.什么时候添加? 2.怎么添加?首先来看第一个问题,答案很简单,当然是在 onCreateViewHolder 中新建 item 布局时添加;


怎么添加呢?可以提前写一个布局文件,准备好这层可以滑动的容器,比如:



其中 SlideLayout 继承自 HorizontalScrollView ,就是这层可以滑动的容器,我们只要把 item 布局塞到 LinearLayout 内部就可以了,怎么塞呢?很简单:



这样就成功的把 item 外层裹上可以滑动的 SlideLayout 了,如果要添加侧滑菜单,同理,像 item 布局一样把菜单布局也塞进去就行了,本库是这样实现的:



linearLayout 的 addView 方法是按添加顺序从左到右排列的,所以可以这样实现。其中有一个问题很明显,当没添加侧滑菜单时,仍然给 item 外层添加了 SlideLayout,这的确属于一个漏洞。


最后再说一下 SlideLayout 的实现,其实十分简单,主要就是控制它的滑动,比如当滑开一半多菜单时松手的话,调用其 smoothScrollTo 方法完全打开。还有就是控制菜单打开的唯一性,我自创的方案与主流的 QQ、微信都不同,感兴趣的可以查看动手打造史上最简单的 Recycleview 侧滑菜单 或阅读源码。


3.如何初始化侧滑菜单


侧滑菜单的初始化包括两部分,一是根据传入的 float 类型数据,初始化侧滑菜单占屏幕宽度的比例,二是初始化侧滑菜单的滑动位置,比如有左侧侧滑菜单时,需要滑动到刚好隐藏掉左侧侧滑菜单的位置。


初始化时机于 onBindViewHolder 中,关键代码如下:



首先看代码的第 1 行,mSlideItems 中存放了所有类型的 item 的相关数据,包括 item 的 layoutId 、菜单的 layoutId 及其宽度比例。获取到此 postion 对应的 item 类型信息后,再根据宽度比例设置菜单的宽度即可。


怎么初始化 SlideLayout 的滑动位置呢?


可以看到程序将侧滑菜单的宽度记录在 SlideLayout 中,有了侧滑菜单的具体宽度,就很容易初始化 SlideLayout 的滑动位置了,重写 SlideLayout 的 onLayout 方法:



4.如何兼容 LinearLayout 和 GridLayout


LinearLayout 和 GridLayout 的兼容包括两部分,一是 item 之间的间距,即分割线在 LinearLayout 与 GridLayout 下都能合理分布;二是头部和底部的宽度,若为 GridLayout ,头部底部宽度应该与 RecycleView 宽度一致。


首先来看第一个问题,在 SlideAdapter 构造函数中是这样设置 item 之间间距的:



SlideItemDecoration 中重写了 getItemOffsets 方法:



代码很简单,如果是 LinearLayout,就把分割线添加在 item 的下方,如果是 GridLayout ,就把分割线添加在 item 的四周。其实严格来说,这不能叫做分割线,只能叫间距,这种情况下如果要设置“分割线”的颜色,就只能设置 RecycleView 的背景色来实现,当然你也可以添加自己的 ItemDecoration 实现更多分割线效果。


来看第二个问题,如何兼容 item、头部底部的宽度,同样在 SlideAdapter 的构造函数中,把 item 和头部底部的宽度先确定下来:



代码 2 行把头部底部的宽度确定了下来,值就是 RecycleView 的宽度。如果是 LinearLayout ,item 的宽度就等同于头部底部的宽度;如果是 GridLayout ,item 的宽度就要除以列数并减去 item 间距值。


把 item 、头部底部的宽度值都确定下来以后,在 onBindViewHolder 中直接设置宽度,就成功的实现兼容 LinearLayout 和 GridLayout 了。


5.如何实现多头部、多底部


多头部、多底部无非就是不同的 viewType , SlideAdapter 中规定 item 的 viewType 范围为 1-99 ,头部、底部对应 viewType 的范围为:



//头部:101~200 private static final int TYPE_HEADER_ORIGIN = 101; //底部:201~ private static final int TYPE_FOOTER_ORIGIN = 201;


相信 100 种 viewType 足够使用了。在 getItemViewType 中确定对应范围:



其中 getHeaderNum、getFooterNum 方法为下:



其中 mHeaders 、mFooters 中分别存储着所有的头部、所有的底部信息,包括 layoutId 和高度比例。确定好 item 、头部及底部的 viewType 后,就可以在 onCreateViewHolder 中根据不同的 viewType 创建不同的 viewHolder 了:



其中的 isHeader、isFooter 方法很简单,根据 viewType 的范围判断即可:



ok,在成功创建对应的头部、底部后,还要注意的就是数据的移位,此时 onBindViewHolder 中提供的 position 不能直接用来索引 data 数据,应该减去头部的数量,比如在调用 ItemBind 接口方法时:



实现原理的部分就介绍这么多吧,其实到这里已经把本库的关键点都拿出来剖析说明了,剩下的比如加载更多等功能都比较简单,当然如果你感兴趣的话可以阅读源码,内容并不多,最后附上本库的所有文件:



总结


这是我的第一个开源库,功力尚浅,如果你在使用过程中遇到了什么问题,随时可以向我反馈,我会第一时间回复并改正。


如果你想在此库的基础上添加自己的功能,欢迎 fork、欢迎 star 。


源码:

https://github.com/yhaolpz/SlideAdapter



优秀人才不缺工作机会,只缺适合自己的好机会。但是他们往往没有精力从海量机会中找到最适合的那个。

100offer 会对平台上的人才和企业进行严格筛选,让「最好的人才」和「最好的公司」相遇。


扫描下方二维码,注册 100offer,谈谈你对下一份工作的期待。一周内,收到 5-10 个满足你要求的好机会!


如果你有想学习的文章直接留言,我会整理征稿。如果你有好的文章想和大家分享欢迎投稿,直接向我投递文章链接即可。

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存